Skip to content

feat(work): watch the work list on a live kanban board - #249

Merged
outofcoffee merged 7 commits into
mainfrom
kanban
Sep 26, 2026
Merged

outofcoffee merged 7 commits into
mainfrom
kanban

Conversation

@outofcoffee

Copy link
Copy Markdown
Collaborator

Adds spinloop work board: a full-screen kanban of a running orchestrator's work list — add items, tail their logs, abort runs and clear failures without leaving the screen.

Summary

  • Four fixed state columns (Backlog, Running, Done, Failed), a card per item, re-read from the work list API on a cadence so cards move as the run works; a dropped API ages the title bar instead of emptying the board.
  • Card detail (enter) shows the whole item — full instructions, dir, tags, timings, failure reason — with its kept output tailed beneath exactly as work logs -f tails it.
  • Add form (n) — a modal over the live board with all five fields at once; the API stays the only judge of an item's shape, and its refusal stands in the form for a corrected send.
  • Abort (a) and remove (x, with a confirm) ride the same API paths the one-shot commands call; refusals read on the status line the way the API states them.
  • Keys are offered only where they would do something for what is selected; piped, the command refuses and names spinloop work list.
  • Docs: the board section in docs/commands/work.md, cross-links from the work-items guide and the commands index, CHANGELOG entry. Closes feat: add TUI kanban board #246.

Implementation details

  • Mirrors the fleet dashboard's three-file split (command+gate / model / renderers) and its rectangular discipline: everything clipped, nothing wrapped, sizes clamped to the frame.
  • charmbracelet/bubbles is taken on for its textinput alone (blink off — a standing surface must stay byte-stable); the grid, cards, detail and hints stay hand-rolled.
  • The suite drives the model with injected tea.KeyMsgs over an httptest fake API (the API's real refusals, and a call log that proves the negatives: declined removals sent nothing); one teatest smoke drives an abort through the real program loop to prove the prog.Send spin-chain wiring no direct test can reach.

Adds `spinloop work board`: four state columns re-read from the work
list API on a cadence, with detail-and-log-tail, in-place add form,
abort and confirm-before-remove — all through the API alone, so
refusals read the way the API states them. A client of the work list
API only, and it refuses a pipe in favour of `work list`.

Closes #246
@outofcoffee outofcoffee added the enhancement New feature or request label Sep 26, 2026
spinloop-agent added 6 commits September 26, 2026 01:27
An action woken its spinner repaint chain by calling prog.Send from
inside Update. The loop reads that channel on the very goroutine
running Update, so the send blocked forever and the whole board went
deaf — the last Enter on the add form was one way to hit it. The chain
is now scheduled as the second command of the action's batch, the
pattern the fleet dashboard already rides; the program expands it in a
goroutine of its own, and the tick handler keeps it restacking until
the call answers.

Tests drive commands through one wbLand helper: it unwraps the batch
to the call, folds the answer in, and lands the follow-up read;
wbAct and wbRound wrap it for their shapes. The teatest smoke now
lands an abort through the real loop, where the batch is expanded as
in the binary — the wiring the directly-driven tests never reached
because they leave send unwired.
The why row was emitted as one line and clipped at the frame, so a
long reason lost its tail — the part an operator opens the detail to
read. It now wraps under the label's room, the red kept on every
row; the log pane gives the height back through the same field count
that sizes it.
Instructions wrapped to the width but nothing capped the field
section's height: a long enough instruction pushed the log pane and
the esc-back footer past the terminal's bottom edge, unreachable in a
view without scrolling. The fields now answer the same discipline the
log pane already kept — keep what fits, and a dim note counts the
rows left behind rather than hiding them unseen. One detailLayout
computation feeds the view and the tail's buffer, so neither can hold
what the frame cannot draw.
…change

The detail's contract now says what the pane actually owes: instructions
and failure reason wrapped to the frame rather than clipped, a record
taller than the terminal truncated honestly with a note counting the
rows left behind, and the keys kept on screen. design and tasks describe
the shipped Batch pattern, not the prog.Send chain that deadlocked the
loop; internals records that trap for the next TUI.
# Conflicts:
#	docs/maintainer/internals.md
@outofcoffee
outofcoffee merged commit f56c643 into main Sep 26, 2026
7 of 8 checks passed
@outofcoffee
outofcoffee deleted the kanban branch September 26, 2026 01:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add TUI kanban board

1 participant